package pa2.node;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;

import pa2.util.Callback;
import pa2.util.EqualityCompare;




public class SimpleNode<K extends EqualityCompare<K>, V, M extends Map<K,V>> extends UnicastRemoteObject 
		implements Node<K, V, M> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3063127676094630906L;
	private final K key;
	private final NodeData<K, V, M> data;
	private Node<K,V,M> left = null;
	private Node<K,V,M> right = null;

	protected SimpleNode(K key, NodeData<K,V,M> data) throws RemoteException {
		super();
		this.key = key;
		this.data = data;
	}

	@Override
	public K getKey() throws RemoteException {
		return this.key;
	}


	@Override
	public NodeData<K, V, M> getData() throws RemoteException {
		return this.data;
	}

	@Override
	public void put(K key, V value, Callback<K,V> callback)
			throws RemoteException {
		if (this.data==null) {
			if (key.compareTo(this.key)<0) {
				this.left.put(key, value, callback);
			} else {
				this.right.put(key, value, callback);
			}
		} else {
//			System.out.println("Put @ Node["+this.key+"]");
			callback.call(key,this.data.put(key, value));
		}
	}

	@Override
	public void get(K key, Callback<K,V> callback) throws RemoteException {
		if (this.data==null) {
			if (key.compareTo(this.key)<0) {
				this.left.get(key, callback);
			} else {
				this.right.get(key, callback);
			}
		} else {
			callback.call(key,this.data.get(key));
		}
	}

	@Override
	public void remove(K key, Callback<K,V> callback) throws RemoteException {
		if (this.data==null) {
			if (key.compareTo(this.key)<0) {
				this.left.remove(key, callback);
			} else {
				this.right.remove(key, callback);
			}
		} else {
			callback.call(key,this.data.remove(key));
		}
	}


	@Override
	public void addChild(Node<K, V, M> child) throws RemoteException {
		if (child.getKey().compareTo(this.key)<0) {
			if (this.left == null) {
//				System.out.println("Node["+this.key+"] set LeftChild["+child.getKey()+"]");
				this.left = child;
			} else {
				this.left.addChild(child);
			}
		} else {
			if (this.right == null) {
//				System.out.println("Node["+this.key+"] set RightChild["+child.getKey()+"]");
				this.right = child;
			} else {
				this.right.addChild(child);
			}
		}
	}


	@Override
	public void removeChild(Node<K, V, M> child) throws RemoteException {
		if (this.left == child) {
			this.left = null;
		} else if (this.right == child) {
			this.right = null;
		} else {
			if (child.getKey().compareTo(this.key)<0) {
				this.left.removeChild(child);
			} else {
				this.right.removeChild(child);
			}
		}
	}

	@Override
	public Node<K, V, M> getLeftChild() throws RemoteException {
		return this.left;
	}

	@Override
	public Node<K, V, M> getRightChild() throws RemoteException {
		return this.right;
	}

}
